package Java多线程和并发.Java并发线程基础;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @program: algorithm
 * @description: 外部线程安排中断
 * @author: 陈恩涛
 * @create: 2022-04-04 10:35
 **/
public class OutThreadInterrupt {

    private static final ScheduledExecutorService cancelService = Executors.newScheduledThreadPool(3);

    public static void timedRun(Runnable r, long timeout, TimeUnit unit) {
        final Thread taskThread = Thread.currentThread();
        System.out.println(taskThread.getName());
        cancelService.schedule(() -> {
            System.out.println(Thread.currentThread().getName());
            taskThread.interrupt();
        }, timeout, unit);
        r.run();
    }

    public static void timedRun2(Runnable r, long timeout, TimeUnit unit) throws InterruptedException {

        class RethrowableTask implements Runnable {
            private volatile Throwable t;

            @Override
            public void run() {
                try {
                    r.run();
                } catch (Throwable t) {
                    this.t = t;
                }
            }

            void rethrow() {
                if (t != null) {
                    throw launderThrowable(t);
                }
            }
        }

        RethrowableTask task = new RethrowableTask();
        Thread taskThread = new Thread(task);
        taskThread.start();
        cancelService.schedule(() -> {
            taskThread.interrupt();
        }, timeout, unit);
        taskThread.join(unit.toMillis(timeout));
        task.rethrow();
    }

    public static RuntimeException launderThrowable(Throwable t){
        if (t instanceof RuntimeException) {
            return (RuntimeException) t;
        } else if (t instanceof Error) {
            throw (Error) t;
        } else {
            throw new IllegalStateException("Not unchecked", t);
        }
    }

    public static void main(String[] args) {
        try {
            timedRun2( () -> {
                System.out.println(Thread.currentThread().getName());
            },2, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
